// rojobot2.v - Project 1 Rojobot for the Digilent Nexys3 board
//
// Copyright Roy Kravitz 2008-2013, 2014
//
// Created By:		Roy Kravitz	
// Last Modified:	31-Dec-2013 (RK)
//
// Revision History:
// -----------------
// Nov-2006		JL	Created this module for the S3 Starter Board
// Nov-2008		RK	Modified for the S3E Starter Board running at 50MHz
// Sep-2012		RK	Modified for the Nexys 3 board running at 100MHz
// Dec-2013		RK	Cleaned up the formatting.  No functional changes
// 
// Description:
// ------------
//   This module implements the Robobot for Project 1 for the Digilent Nexys3 board
//   Display is via the Four digit 7-segment display on the Nexys3
///////////////////////////////////////////////////////////////////////////

`timescale  1 ns / 1 ns
module RojoBot2(
	input 				clk,
	input				reset,
	input				left_fwd, left_rev, right_fwd, right_rev,
    
    output reg [4:0]	ones = 0, tens = 0, hundreds = 0,
    output reg [4:0]	mi_segs,
 
    input	   [1:0]	turn_speed,		// Rojobot turn speed   
    output reg [7:0]	chase_segs		// chase segments (for debug)	
    );
    
    parameter simulate = 0; // override to 1 in testbench for simulation; leave at 0 for synthesis
    localparam tick_cnt = simulate ? 26'd5          // rojobot clock when simulating
                                   : 26'd19_999_999; // rojobot count when running on HW (5Hz)                                     

	//internal registers	
	reg [25:0] 			tick_count = 0;					// clock divider counter
	reg 				tick = 0;						// 5Hz or 10Hz clock enable
	reg 				blink = 0;						// blinker for forward/reverse motion indication
	reg [3:0]		blink_cnt = 0;					// blink counter.  Blink speed is different than tick
	reg [5:0]			chase = 6'b111110;				// chaser for turning motion indication
	reg [4:0]			mi_segs_turn_ind = 31;			// Hex code for turn indicator segments
	reg 				up, dn, fast, fwd, rev, stop;	// motion modes decoded from pushbuttons
	
	reg					tick_ind = 0;					// 5Hz or 10Hz clock visible clock pulse
	reg	[25:0]			turn_speed_int;					// turn speed

	
	// calculate turn speed
	always @* begin
		case ({fast, turn_speed})
			3'b0_00:	turn_speed_int = tick_cnt >> 0;		// slow, acceleration = 0x
			3'b0_01:	turn_speed_int = tick_cnt >> 1;		// slow, acceleration = 2x
			3'b0_10:	turn_speed_int = tick_cnt >> 2;		// slow, acceleration = 4x
			3'b0_11:	turn_speed_int = tick_cnt >> 3;		// slow, acceleration = 8x
			
			3'b1_00:	turn_speed_int = tick_cnt >> 1;		// fast, acceleration = 2x
			3'b1_01:	turn_speed_int = tick_cnt >> 2;		// fast, acceleration = 4x
			3'b1_10:	turn_speed_int = tick_cnt >> 3;		// fast, acceleration = 8x
			3'b1_11:	turn_speed_int = tick_cnt >> 4;		// fast, acceleration = 16x
		endcase		
	end  // always - calculate turn speed
	
	// generate tick
	always @(posedge clk) begin
		if (tick_count == turn_speed_int) begin 
		    tick <= 1;
		    tick_count <= 0;
			tick_ind <= ~tick_ind;
		end
		else begin
		    tick_count <= tick_count + 1'b1;
		    tick <= 0;
        end
	end // always - generate tick
         
   // decode pushbuttons into forward, reverse and stopped motion modes         
    always @* begin
        case ({left_fwd, left_rev, right_fwd, right_rev})
            4'b1010: {fwd, rev, stop} = 3'b100; // moving forward
            4'b0101: {fwd, rev, stop} = 3'b010; // moving in reverse
            4'b0000, // no buttons pushed                 - stopped 
            4'b0011, // right fwd and rev cancel          - stopped
            4'b1100, // left fwd and rev cancel           - stopped
            4'b1111: // right and left fwd and rev cancel - stopped
                     {fwd, rev, stop} = 3'b001;            
            default: {fwd, rev, stop} = 3'b000; // turning modes decoded in case statement below
        endcase
	end // always - decode pushbutton to fwd, rev, and stopped
        
    // decode pushbuttons into turning modes: count up, count down and speed (fast/slow)
    always @* begin
        case ({left_fwd, left_rev, right_fwd, right_rev})
            4'b1000: {up, dn, fast} = 3'b100; // turn right 1x
            4'b0001: {up, dn, fast} = 3'b100; // turn right 1x
            4'b1001: {up, dn, fast} = 3'b101; // turn right 2x
            4'b0010: {up, dn, fast} = 3'b010; // turn left 1x
            4'b0100: {up, dn, fast} = 3'b010; // turn left 1x
            4'b0110: {up, dn, fast} = 3'b011; // turn left 2x   
            default: {up, dn, fast} = 3'b000; // not turning
        endcase 
	end // always - decode pushbuttons to turning modes        
    
    // chaser for turning motion indication  
	always @(posedge clk or posedge reset) begin
		if (reset) begin
			chase <= 6'b111110;
		end
		else begin
			if (tick) begin
					if (up) chase <= {chase[0], chase[5:1]}; // rotate clockwise
					if (dn) chase <= {chase[4:0], chase[5]}; // rotate ccw	        
			end
			chase_segs <= {turn_speed[1:0], 1'b0, chase[4:0]};
		end
	end
    
    // blinker for forward/reverse motion indication 
	always @(posedge clk) begin
		if (tick) begin
			blink_cnt = blink_cnt + 1'b1;
			if (blink_cnt == 4'd5) begin	// tick is 5Hz, blink is 1Hz
				 blink <= ~blink;
				 blink_cnt = 0;
			 end
		end
	end // always - blinker for fwd/rev motion indication
    
    // 7-segment motion indicator display selector
    always @* begin
        case (1'b1) // synthesis parallel_case
            stop:    mi_segs = 5'd22;							// light segment g, no blink
            fwd:     mi_segs = blink ? 5'd16 : 5'd31;		// light segment a, blink
            rev:     mi_segs = blink ? 5'd19 : 5'd31;		// light segment d  blink        
            default: mi_segs = mi_segs_turn_ind;			// light segment per turn indicator            		
        endcase
	end // always - 7-segment motion indicator display selector
        
	// 7-segment to hex code converter for turn indicator
	always @* begin
		casex (chase)
			6'b0xxxxx:	mi_segs_turn_ind = 5'd16;		// light segment a
			6'bx0xxxx:	mi_segs_turn_ind = 5'd17;		// light segment b
			6'bxx0xxx:	mi_segs_turn_ind = 5'd18;		// light segment c
			6'bxxx0xx:	mi_segs_turn_ind = 5'd19;		// light segment d
			6'bxxxx0x:	mi_segs_turn_ind = 5'd20;		// light segment e
			6'bxxxxx0:	mi_segs_turn_ind = 5'd21;		// light segment f
		endcase 
	end // always - 7-segment to hex converter for turn indicator 
		
    
    // 360 degree compass up/down counter    
	always @(posedge clk or posedge reset) begin
		if (reset) begin
			ones <= 0;
			tens <= 0;
			hundreds <= 0;
		end
		else begin
			if (tick) begin
				// ones digit
				if (up)
					if (ones == 9) ones <= 0;
					else ones <= ones + 1'b1;
  		        
				if (dn)
					if (ones == 0) ones <= 9;
					else ones <= ones - 1'b1;
        
					// tens digit
					if (up && (ones == 9)) // increment tens digit
						if (((hundreds == 3) && (tens == 5)) || (tens == 9)) tens <= 0; 
						else tens <= tens + 1'b1;
                
					if (dn && (ones == 0)) // decrement tens digit
						if (tens == 0) 
							if (hundreds == 0) tens <= 5; // rollover 359 to 000
							else tens <= 9;
						else tens <= tens - 1'b1;
                
					// hundreds digit
					if (up && (hundreds == 3) && (tens == 5) && (ones == 9)) hundreds <= 0; // rollover 359 to 000
					else if (up && (tens == 9) && (ones == 9)) hundreds <= hundreds + 1'b1;    // increment hundreds digit
					
					if (dn && (tens == 0) && (ones == 0)) // decrement hundreds digit
						if (hundreds == 0) hundreds <= 3; // rollover 000 to 359
						else hundreds <= hundreds - 1'b1;
			end
		end
    end
 
endmodule